import os

from PyQt5.QtWidgets import QLabel
from PyQt5.QtCore import pyqtSignal, Qt, QPoint, QRect
from PyQt5.QtGui import QPixmap, QPainter, QColor, QFont, QPen, QBrush

from common.objects.area_object import AreaObject
from common.settings import Settings
from common.utils.NovishLogger import logger
from ui.base.widgets.ImgViewer import ShowImgPage


class ClickableLabel(QLabel):
    # 定义一个点击信号，带有一个 QPoint 参数，表示点击的坐标
    clicked_signal = pyqtSignal(QPoint)
    bbox_clicked_signal = pyqtSignal(str, QPoint)  # 新增信号，用于通知点击了哪个 bbox

    def __init__(self, parent=None, show_image=None):
        super(ClickableLabel, self).__init__()
        self.parent = parent
        # 设置鼠标指针为手型，表示可点击
        self.setCursor(Qt.PointingHandCursor)
        # 初始化图片
        self.setPixmap(QPixmap())
        # 存储 bbox 数据
        self.bboxes = []  # 每个 bbox 是一个字典，包含 'rect' 和 'class_name'
        # 连接点击信号到默认槽函数
        self.clicked_signal.connect(self.on_label_clicked)
        self.bbox_clicked_signal.connect(self.on_bbox_clicked)
        self._ui_area_item_list = []
        if show_image is None:
            self.show_image_widget = ShowImgPage(self.parent)
        else:
            self.show_image_widget = show_image
        self.img_path = None
        self.path_list = []
        self.MAX_LABEL_HEIGHT = 560
        self.setMaximumHeight(self.MAX_LABEL_HEIGHT)
        self._img_height = 560

    @property
    def ui_area_item_list(self):
        return self._ui_area_item_list

    @ui_area_item_list.setter
    def ui_area_item_list(self, value):
        # logger.debug(f"value:{value}")
        self._ui_area_item_list = value
        # # 每次到一个新的工件，展示第一张图
        # if len(self._ui_area_item_list) > 0:
        #     area_obj: AreaObject = self._ui_area_item_list[0]
        #     self.path_list = area_obj.defect_img_path_list
        #
        #     self.img_path = self.path_list[0]
        #     fst_det_obj = area_obj.first_det_obj
        #     self.show_image_widget.content.ori_img_path = fst_det_obj.ori_img_path
        #     self.show_image_widget.content.det_img_path = fst_det_obj.det_img_path
        # else:
        #     self.img_path = r'resource/static/black_ok.jpg'
        # if self.img_path is not None and os.path.exists(self.img_path):
        #     self.show_img(QPixmap(str(self.img_path)))
        # else:
        #     logger.warning(f"Show img not exists: {self.img_path}; maybe not enough time for saving img")
        self.update_bboxes()

    def set_image(self, image_path):
        """设置要显示的图片"""
        pixmap = QPixmap(image_path)
        self._img_height = min(pixmap.height(), self.MAX_LABEL_HEIGHT)
        logger.debug(f"self._img_height:{self._img_height}")
        self._pixmap = pixmap
        self.setPixmap(pixmap)
        self._updatePixmap()

    def _updatePixmap(self):
        if self._pixmap is not None and not self._pixmap.isNull():
            # Calculate new size preserving aspect ratio
            pixmap_ratio = self._pixmap.width() / self._pixmap.height()
            label_height = self.height()
            resized_width = int(label_height * pixmap_ratio)
            resized_height = label_height
            scaled_pixmap = self._pixmap.scaled(
                resized_width,
                resized_height,
                Qt.KeepAspectRatio,
                Qt.SmoothTransformation
            )
            logger.info(f"set pixmap size {(resized_width, resized_height)}; {self.size()}")
            super().setPixmap(scaled_pixmap)

    def resizeEvent(self, event):
        """处理 Label 大小变化事件，重新计算缩放比例和偏移量"""
        super(ClickableLabel, self).resizeEvent(event)
        logger.info(f"label resize to {self.width()} {self.height()}")
        self._updatePixmap()
        self.update_bboxes()  # 重新计算 bbox 的缩放和偏移

    def update_bboxes(self, bbox_format='ltrb'):
        area_obj_list = self._ui_area_item_list
        # 获取图片和 QLabel 的大小
        pixmap = self.pixmap()
        if not pixmap or pixmap.isNull():
            return
        label_size = self.size()
        pixmap_size = pixmap.size()

        # 计算缩放比例
        logger.info(f"click label:{label_size.width()} {label_size.height()}; "
                    f"pixmap: {pixmap_size.width()}; {pixmap_size.height()}")
        scale_x = label_size.width() / pixmap_size.width()
        scale_y = label_size.height() / pixmap_size.height()

        # 选择较小的比例以保持宽高比
        scale = min(scale_x, scale_y)

        # 计算偏移量（居中对齐）
        offset_x = (label_size.width() - pixmap_size.width() * scale) / 2
        offset_y = (label_size.height() - pixmap_size.height() * scale) / 2
        logger.info(f"scale_x, scale_y:{scale_x} {scale_y}; "
                    f"offset_x, offset_y: {offset_x}; {offset_y}; self._img_height:{self._img_height}")
        logger.debug(f"area_obj_list:{area_obj_list}")
        factor = label_size.height() / self._img_height  #
        logger.debug(f"factor:{factor}")
        for area_obj in area_obj_list:
            # logger.debug(f"area_obj:{area_obj.__dict__}")
            bbox = area_obj.rectangle_point
            if bbox_format == 'ltrb' and (bbox is not None):
                # 如果是 left, top, right, bottom 格式，转换为 left, top, width, height
                left, top, right, bottom = bbox
                width = right - left
                height = bottom - top
                rect = QRect(left, top, width, height)
                # rect是左侧(1033x411); 右侧:734x552尺度下的, 转换到scale以后的尺度
                # 将 bbox 坐标从图片的原始坐标系转换到 QLabel 的坐标系

                scaled_rect = QRect(
                    int((rect.x() * scale) * factor + offset_x),
                    int((rect.y() * scale + 50) * factor + offset_y),
                    int(rect.width() * factor * scale),
                    int(rect.height() * factor * scale)
                )

                area_obj.scaled_rectangle_point = scaled_rect
        # 刷新界面
        self.update()

    # 下面代码需要修改：绘制textlabel的位置现在是在矩形的上放，需要修改为在以矩形的中心为起点，保持横坐标不变，纵坐标到图片的上方区域，并绘制textlabel

    def paintEvent(self, event):
        """重写 paintEvent 方法，绘制 bbox 和连接线"""
        super(ClickableLabel, self).paintEvent(event)

        painter = QPainter(self)
        pen = QPen(QColor(255, 0, 0))  # 红色边框
        pen.setWidth(2)
        painter.setPen(pen)
        font = QFont("Arial", 8, QFont.Bold)
        painter.setFont(font)

        # 获取图片和 QLabel 的大小
        pixmap = self.pixmap()
        if not pixmap or pixmap.isNull():
            return
        img_width, img_height = pixmap.size().width(), pixmap.size().height()
        for area_obj in self._ui_area_item_list:
            # TODO 可以设为true查看所有的区域
            if not area_obj.flag_ok:
                # logger.debug(f"area_obj.det_obj_list:{area_obj.det_obj_list}")
                scaled_rect = area_obj.scaled_rectangle_point
                area_name = area_obj.area_id
                ch_area_name = Settings.ITEM_SETTINGS.AREA_MAP[area_name].get('ch_name', 'unknown')
                first_ng_det_obj = area_obj.first_ng_det_obj
                first_ng_det_class = first_ng_det_obj.chinese_class_name if first_ng_det_obj else None
                if first_ng_det_class:
                    # 矩形中心点
                    center_x = scaled_rect.center().x()
                    center_y = scaled_rect.center().y()

                    # 标签放在rect的中心
                    end_x = center_x
                    # 在矩形中心显示区域名
                    painter.drawText(end_x, center_y, ch_area_name)
                    # 直线终点位置：保持横坐标不变，纵坐标设为100
                    # 计算文本标签的位置
                    text_rect = painter.boundingRect(0, 0, self.width(), self.height(), Qt.AlignLeft,
                                                     first_ng_det_class)
                    text_start_x = scaled_rect.x()
                    text_start_y = scaled_rect.y()  # 下方留出一些空间

                    # 设置回原始颜色并绘制文本标签
                    pen.setColor(QColor(255, 0, 0))
                    painter.setPen(pen)
                    # 保存当前画布状态
                    painter.save()
                    # 平移到文本起始点，并旋转画布90度
                    painter.translate(text_start_x, text_start_y)
                    char_spacing = 20  # 字符间距
                    for i, char in enumerate(first_ng_det_class):
                        # 计算每个字符的位置
                        char_x = 5
                        char_y = (i + 1) * char_spacing
                        # 绘制单个字符
                        painter.drawText(char_x, char_y, char)
                    painter.restore()
                # 恢复默认设置并绘制矩形
                pen.setColor(QColor(255, 0, 0))
                painter.setPen(pen)
                painter.drawRect(scaled_rect)

    def mouseReleaseEvent(self, event):
        """处理鼠标释放事件，判断点击是否在某个 bbox 内"""
        if event.button() == Qt.LeftButton:
            click_pos = event.pos()

            # 获取图片和 QLabel 的大小
            pixmap = self.pixmap()
            if not pixmap or pixmap.isNull():
                return

            label_size = self.size()
            pixmap_size = pixmap.size()

            # 计算缩放比例
            scale_x = label_size.width() / pixmap_size.width()
            scale_y = label_size.height() / pixmap_size.height()

            # 选择较小的比例以保持宽高比
            scale = min(scale_x, scale_y)

            for area_obj in self._ui_area_item_list:
                scaled_rect = area_obj.scaled_rectangle_point
                if scaled_rect.contains(click_pos):
                    # 如果点击在某个 bbox 内，发出 bbox_clicked 信号
                    self.bbox_clicked_signal.emit(area_obj.area_id, click_pos)
                    break
            else:
                # 如果没有点击在任何 bbox 内，发出普通的 clicked 信号
                self.clicked_signal.emit(click_pos)
        super(ClickableLabel, self).mouseReleaseEvent(event)

    def show_img(self, img):
        """
        显示图像。

        将指定的图像显示在图像显示窗口中。此方法首先将路径列表和当前图像路径传递给图像显示窗口，
        然后设置窗口标题为当前图像文件名，最后显示图像内容并使窗口可见。

        参数:
        img (str): 图像文件路径。

        返回:
        无
        """
        # 将当前实例的路径列表和图像路径传递给图像显示窗口
        self.show_image_widget.path_list = self.path_list
        self.show_image_widget.current_path = self.img_path
        # 从图像路径中提取文件名并设置为窗口标题
        window_title = self.img_path.split('\\')[-1]
        self.show_image_widget.setWindowTitle(window_title)
        # 在图像显示窗口中显示图像内容
        self.show_image_widget.content(img)
        self.show_image_widget.content.img_path = self.img_path
        # 显示图像显示窗口
        self.show_image_widget.show()

    def on_label_clicked(self, position):
        """默认的点击处理函数"""
        logger.info(f"Label clicked at position: {position}")
        pass

    def on_bbox_clicked(self, area_id, position):
        """处理 bbox 被点击的默认槽函数"""
        logger.debug(f"area_id:{area_id}")
        clicked_area_obj = None
        for area_obj in self._ui_area_item_list:
            if area_obj.area_id == area_id:
                clicked_area_obj = area_obj
                break
        # area_obj: AreaObject = self._ui_area_item_list[area_id]
        logger.info(f"area.area_id '{clicked_area_obj.area_id}' clicked at position: {position}")
        self.path_list = clicked_area_obj.defect_img_path_list
        if self.path_list:
            self.img_path = self.path_list[0]
            if self.img_path is not None and os.path.exists(self.img_path):
                fst_det_obj = clicked_area_obj.first_det_obj
                self.show_image_widget.content.ori_img_path = fst_det_obj.ori_img_path
                self.show_image_widget.content.det_img_path = fst_det_obj.det_img_path
                self.show_img(QPixmap(str(self.img_path)))
            elif self.pixmap():
                self.show_img(self.pixmap())
        else:
            logger.warning(f"clicked_area_obj: {clicked_area_obj.__dict__} does not have image path")
